// i.r(t), i.d(t, { default: () => FloorsViewDataModule })
import Module from "./Module"
import Logger from "../utils/Logger"
import CameraModule from "./CameraModule"
import LocaleModule from "./LocaleModule"
import { KeyEvent } from "../event/KeyEvent"
import SweepData from "../data/SweepData"
import ViewmodeData from "../data/ViewmodeData"
import CameraData from "../data/CameraData"
import MeshData from "../data/MeshData"
import { BeginSwitchViewmodeMessage } from "../message/viewmode.message"
import RaycasterData from "../data/RaycasterData"
import TourData from "../data/TourData"
import ApplicationData from "../data/ApplicationData"
import { ApplicationChangeMessage } from "../message/app.message"
import FloorsData from "../data/FloorsData"
import configConst from "../constant/config.const"
class FloorsRenderer {
  getAngleModifier: any
  pose: any
  floorsViewData: FloorsViewData
  viewmodeData: ViewmodeData
  raycasterData: RaycasterData
  meshData: MeshData
  touchDevice: any
  getDiscardDistance: (e: any) => number
  constructor(e, t, i, n, s, r, o) {
    this.getAngleModifier = e
    this.pose = t
    this.floorsViewData = i
    this.viewmodeData = n
    this.raycasterData = s
    this.meshData = r
    this.touchDevice = o
    this.getDiscardDistance = e => {
      if (e) {
        return 4 + (this.pose.focalDistance * configConst.fadeConfig.DISCARD_FOCAL_MULTI || 0)
      }
      return 0
    }
  }
  activate() {}
  init() {}
  dispose() {}
  deactivate() {
    const { floorOpacity: e, roomFadeDist: t } = this.meshData.meshGroupVisuals
    for (const e of this.meshData.meshGroups.rooms) t.set(e.meshGroup, e.meshSubgroup, 0)
    for (const t of this.meshData.meshGroups.floors.values()) e.set(t.meshGroup, 0)
  }
  beforeRender() {
    const e = this.floorsViewData.nearestFloor,
      t = this.floorsViewData.transition.progress.active,
      i = !(!e || this.viewmodeData.isInside()),
      n = configConst.fadeConfig.FADE_OPAQUE
    let s = n,
      r = n
    const o = this.getAngleModifier()
    i &&
      (this.floorsViewData.floorSelectModeEnabled && (this.viewmodeData.isDollhouse() || this.viewmodeData.isOrthographic())
        ? ((s = n * o * configConst.fadeConfig.FADE_IN_VALUE), (r = s * configConst.fadeConfig.FADE_BELOW_MULT + configConst.fadeConfig.FADE_BELOW_START))
        : ((s = configConst.fadeConfig.FADE_ABOVE), (r = configConst.fadeConfig.FADE_BELOW)))
    for (const { meshGroup: e } of this.meshData.meshGroups.floors) {
      const i = this.floorsViewData.floors.getFloorByMeshGroup(e)
      let o = n
      const a = this.isBelowSelectedFloor(i) ? r : s
      let l = funcUtil.getMax(a + configConst.fadeConfig.FADE_IN_HOVER_BOOST_VALUE, 0, 1)
      this.floorsViewData.roomSelectModeActive && (l = a),
        (o = this.isHoveredFloor(null == i ? void 0 : i.id) && !t && a > 0 ? l : a),
        (o = this.isFloorTransitioningOut(i) ? a : o),
        (o = this.isSelectedFloor(null == i ? void 0 : i.id) || this.isFloorTransitioningIn(i) ? n : o),
        (o = this.clampForViewmodeTransitions(o)),
        this.meshData.meshGroupVisuals.floorOpacity.set(e, o)
    }
    const a = !(!e || !this.viewmodeData.isDollhouse())
    for (const [e, t] of this.meshData.meshGroups.roomsByFloor.entries())
      for (const i of t) {
        const t = this.getDiscardDistance(a && i.meshGroup > e)
        this.meshData.meshGroupVisuals.roomFadeDist.set(i.meshGroup, i.meshSubgroup, t)
      }
  }
  render() {}
  clampForViewmodeTransitions(e) {
    if (this.viewmodeData.currentMode === viewmodeEnum.Transition) {
      const { to: t } = this.viewmodeData.transition
      if (t === viewmodeEnum.Panorama) return Math.max(1 - this.meshData.meshTextureOpacity.value, e)
    }
    return e
  }
  isHoveredFloor(e) {
    if (
      void 0 !== e &&
      this.raycasterData.hit &&
      (this.viewmodeData.isDollhouse() || this.viewmodeData.isOrthographic()) &&
      !this.touchDevice &&
      this.floorsViewData.isNavigable(e)
    ) {
      const t = this.raycasterData.hit.object
      if (roomFunc.hasFloorId(t)) return e === t.floorId
    }
    return !1
  }
  isSelectedFloor(e) {
    const t = this.floorsViewData.nearestFloor
    return !t || !(!e || t.id !== e)
  }
  isBelowSelectedFloor(e) {
    const t = this.floorsViewData.nearestFloor
    return !!(e && t && t.index > e.index)
  }
  isFloorTransitioningIn(e) {
    return !(!e || !this.floorsViewData.transition.progress.active || (this.floorsViewData.transition.to && this.floorsViewData.transition.to !== e.id))
  }
  isFloorTransitioningOut(e) {
    return !(
      !e ||
      !this.floorsViewData.transition.progress.active ||
      (this.floorsViewData.transition.from && this.floorsViewData.transition.from !== e.id && this.floorsViewData.transition.to === e.id)
    )
  }
}
import OpenDeferred from "../utils/OpenDeferred"
import transitionTypeEnum from "../enum/transitionType.enum"
import { NavigateToSweepCommand } from "../command/navigate.command"
import * as THREE from "three"
import Vectors from "../three/Vectors"
import L from "../math/69626"
import R from "../math/51263"
import k from "../math/57051"
import { InvalidFloorException } from "../exception/floor.exception"
import { SetCurrentSweepCommand } from "../command/sweep.command"
class FloorsNavigation {
  engine: EngineContext
  floorsData: FloorsData
  floorsViewData: FloorsViewData
  sweepData: SweepData
  cameraData: CameraData
  cameraModule: CameraModule
  viewmodeData: ViewmodeData
  updateCurrentFloor: any
  meshData: MeshData
  FLOOR_TRANSITION_TIME: number
  MOVE_TO_BLACK_TRANSITION_TIME: number
  moveFloorUp: (e?: boolean, t?: any) => any
  moveFloorDown: (e?: boolean, t?: any) => any
  moveToFloor: any
  constructor(e, t, i, n, s, r, o, a, l) {
    this.engine = e
    this.floorsData = t
    this.floorsViewData = i
    this.sweepData = n
    this.cameraData = s
    this.cameraModule = r
    this.viewmodeData = o
    this.updateCurrentFloor = a
    this.meshData = l
    this.FLOOR_TRANSITION_TIME = 500
    this.MOVE_TO_BLACK_TRANSITION_TIME = 2e3
    this.moveFloorUp = (e = !1, t) => {
      const i = this.floorsViewData.currentFloorId,
        n = this.floorsViewData.getNavigableFloorIds(),
        s = i ? n.indexOf(i) : -1
      let r = n[s + 1]
      return void 0 === r && (r = this.viewmodeData.isInside() ? n[n.length - 1] : n[0]), this.moveToFloor(r, e, t)
    }
    this.moveFloorDown = (e = !1, t) => {
      const i = this.floorsViewData.currentFloorId,
        n = this.floorsViewData.getNavigableFloorIds(),
        s = i ? n.indexOf(i) : n.length
      let r = n[s - 1]
      return void 0 === r && (r = this.viewmodeData.isInside() ? n[0] : n[n.length - 1]), this.moveToFloor(r, e, t)
    }
    this.moveToFloor = (e, t = !1, i, n) => {
      const s = this.floorsViewData.currentFloorId,
        r = s === e,
        o = this.floorsViewData.totalFloors < 2 && !e,
        a = e ? this.floorsViewData.floors.getFloor(e) : null
      if (r || o || !this.floorsViewData.floorsEnabled) return this.updateCurrentFloor(e), OpenDeferred.resolve()
      if (a && !this.canMoveToFloor(a, t)) return OpenDeferred.reject(new InvalidFloorException("Invalid floor ID"))
      this.engine.broadcast(new StartMoveToFloorMessage(s, e)), void 0 === i && (i = this.FLOOR_TRANSITION_TIME)
      const l = new OpenDeferred()
      let c
      this.floorsViewData.transitionToFloor(s, e, i, l.nativePromise()), this.floorsViewData.commit()
      let h,
        d = n
      if (this.viewmodeData.isInside()) {
        const t = e => e => this.floorsViewData.isCurrentOrAllFloors(e.floorId),
          i = !!e ? R.nK : t,
          s = [R._T(), R._k(), i(e)],
          r = [k.l0(n || this.cameraData.pose.position)],
          o = this.sweepData.sortByScore(s, r).shift()
        o && ((d = o.sweep.position), (c = o.sweep.id))
      } else null !== e && this.engine.commandBinder.issueCommand(new SetCurrentSweepCommand())
      h = t ? Promise.resolve() : this.getCameraTransition(e, i, c, d)
      const u = this
      const p = OpenDeferred.all([l, h])
      this.engine.startGenerator(function* () {
        let e = Date.now()
        for (; u.floorsViewData.transition.progress.active; ) {
          yield new NullGeneratorResult()
          const t = Date.now(),
            i = t - e
          u.floorsViewData.transition.progress.tick(i), u.floorsViewData.commit(), (e = t)
        }
        u.updateCurrentFloor(u.floorsViewData.transition.to), l.resolve()
      })
      return p
    }
  }
  moveToFloorIndex(e, t = !1, i, n) {
    let s = null
    if (-1 !== e) {
      const t = this.floorsViewData.floors.getFloorAtIndex(e)
      if (!t) return OpenDeferred.reject(new InvalidFloorException(`Invalid floor index ${e}`))
      s = t.id
    }
    return this.moveToFloor(s, t, i, n)
  }
  canMoveToFloor(e, t = !1) {
    if (!e) return !1
    const i = this.floorsViewData.transition.progress.active
    const n = this.cameraData.canTransition() || t
    const s = e.index <= this.floorsViewData.totalFloors - 1
    const r = e.index >= -1
    return !i && n && s && r
  }
  getCameraTransition(e, t, i, n) {
    if (this.viewmodeData.currentMode === viewmodeEnum.Dollhouse || this.viewmodeData.currentMode === viewmodeEnum.Floorplan) {
      const i = this.getPoseForFloor(e, n)
      return this.cameraModule
        .moveTo({
          transitionType: transitionTypeEnum.Interpolate,
          pose: i.pose,
          focalDistance: i.focalDistance,
          transitionTime: t
        })
        .nativePromise()
    }
    return this.viewmodeData.isInside() && i
      ? this.engine.commandBinder.issueCommand(
          new NavigateToSweepCommand({
            transition: transitionTypeEnum.MoveToBlack,
            sweep: i,
            transitionTime: this.MOVE_TO_BLACK_TRANSITION_TIME
          })
        )
      : Promise.resolve()
  }
  getPoseForFloor(e, t) {
    const { position: i, rotation: n } = this.cameraData.pose
    const s = e ? this.floorsData.getFloor(e) : null
    const r = s ? s.medianSweepHeight() : this.meshData.center.y
    const o = s ? s.center : this.meshData.center
    o.setY(r)
    const a = Vectors.FORWARD.clone().applyQuaternion(n)
    const l = i.clone()
    let c: THREE.Quaternion, h: number
    if (t) {
      const e = i.clone().addScaledVector(a, this.cameraData.pose.focalDistance),
        n = new THREE.Vector3().set(0, i.y, 0),
        s = new THREE.Vector3().set(0, e.y, 0),
        o = n.distanceTo(s)
      l.setY(r + o)
      const d = e.clone().setY(t.y)
      h = d.distanceTo(l)
      this.viewmodeData.isDollhouse() && (c = L.n0(l, d))
    } else {
      const e = (s ? s.size.y : F) / 2 + F * -a.y
      l.setY(r + e)
      h = l.distanceTo(o)
    }
    return { focalDistance: h, pose: { position: l, rotation: c } }
  }
}
const F = 8
import FloorsViewData from "../data/FloorsViewData"
import { ShowAllFloorsCommand, MoveToFloorCommand, MoveToFloorIndexCommand } from "../command/floor.command"
import G from "../math/79437"
import z from "../math/19674"
import W from "../math/7170"
class FloorsSelectModeHelper {
  floorsViewData: FloorsViewData
  viewmodeData: ViewmodeData
  pose: any
  vectors: { lookDir: THREE.Vector3; flattenedLookDir: THREE.Vector3 }
  constructor(e, t, i) {
    this.floorsViewData = e
    this.viewmodeData = t
    this.pose = i
    this.vectors = {
      lookDir: new THREE.Vector3(),
      flattenedLookDir: new THREE.Vector3()
    }
    this.getAngleModifier = this.getAngleModifier.bind(this)
  }
  update() {
    const e = this.getAngleModifier()
    const t = 1 === this.floorsViewData.totalFloors
    const i = !!this.floorsViewData.nearestFloor
    const n = !this.viewmodeData.isInside() && !this.viewmodeData.transitionActive()
    this.floorsViewData.roomSelectModeActive = n && (t || (i && e < 1) || this.viewmodeData.isFloorplan())
    this.floorsViewData.floorSelectModeActive = n && 1 === e && !t
    this.floorsViewData.showFloorSelection =
      !this.viewmodeData.transitionActive() && (this.viewmodeData.isDollhouse() || this.viewmodeData.isFloorplan()) && i && !t
    this.floorsViewData.floorSelectable = this.floorsViewData.floorSelectModeEnabled && (this.viewmodeData.isDollhouse() || this.viewmodeData.isOrthographic())
  }
  getAngleModifier() {
    const e = this.vectors.lookDir.copy(Vectors.FORWARD).applyQuaternion(this.pose.rotation)
    const t = this.vectors.flattenedLookDir.copy(e).setY(0)
    const i = e.angleTo(t) * W.MN
    const n = configConst.fadeConfig.FADE_IN_START_ANGLE
    const s = configConst.fadeConfig.FADE_IN_END_ANGLE
    const r = 1 - z.dS(i, n, s, 0, 1)
    return G.FG(r, 0, 1, 1)
  }
}
import browserUtil from "../utils/browser.util"
import AggregateSubscription from "../utils/AggregateSubscription"
import Comparator from "../utils/Comparator"
import { SetMouseCursorCommand } from "../command/cursor.command"
import SettingsData from "../data/SettingsData"
import { EndSwitchViewmodeMessage } from "../message/viewmode.message"
import SymbolList from "../SymbolList"
import optionsKeyEnum from "../enum/optionsKey.enum"
import { appTypeMin } from "../enum/appType.enum"
import cursorEnum from "../enum/cursor.enum"
import funcUtil from "../utils/func.util"
import { roomFunc } from "../utils/room.util"
import { EndMoveToSweepMessage } from "../message/sweeps.messge"
import keyConst from "../constant/key.const"
import { NullGeneratorResult } from "../engine/EngineGenerators"
import { EndMoveToFloorMessage, StartMoveToFloorMessage } from "../message/floor.message"
import hotKeyEnum, { KeyState } from "../enum/hotKey.enum"
import viewmodeEnum from "../enum/viewmode.enum"
import { isPanOrMesh } from "../utils/viewmode.util"
import { HoverEvent, UnhoverEvent } from "../event/GestureEvent"
import EngineContext from "../EngineContext"
import InputIniModule from "./InputIniModule"
const te = new Logger("floors-view-data")
export default class FloorsViewDataModule extends Module {
  onEndMoveToSweepMessage: (e: any) => void
  sweepData: SweepData
  onMoveToFloorCommand: (e: any) => Promise<any>
  floorNavigation: FloorsNavigation
  onMoveToFloorIndexCommand: (e: any) => Promise<any>
  onShowAllFloorsCommand: (e: any) => Promise<void>
  engine: EngineContext
  applicationChanged: () => void
  floorsViewData: FloorsViewData
  config: any
  updateFloorSelectMode: () => void
  floorsSelectModeHelper: FloorsSelectModeHelper
  floorSelectFeatureEnabledCheck: () => void
  settingsData: SettingsData
  applicationData: ApplicationData
  floorsData: FloorsData
  viewmodeData: ViewmodeData
  cameraData: CameraData
  input: InputIniModule
  raycasterData: RaycasterData
  constructor() {
    super(...arguments)
    this.name = "floors-viewdata"
    this.onEndMoveToSweepMessage = e => {
      const t = this.sweepData.getSweep(e.toSweep)
      t && this.updateCurrentFloor(t.floorId)
    }
    this.onMoveToFloorCommand = async e => this.floorNavigation.moveToFloor(e.floorId, e.suppressCameraMovement, e.transitionTime, e.focusPoint)
    this.onMoveToFloorIndexCommand = async e => this.floorNavigation.moveToFloorIndex(e.floorIndex, e.suppressCameraMovement, e.transitionTime, e.focusPoint)
    this.onShowAllFloorsCommand = async e => {
      const t = "boolean" == typeof e.moveCamera && !e.moveCamera
      await this.engine.commandBinder.issueCommand(new MoveToFloorCommand(null, t))
    }
    this.applicationChanged = () => {
      this.floorsViewData.updateViewData()
    }
    this.updateCurrentFloor = e => {
      this.config.allowFloorChanges &&
        this.floorsViewData.currentFloorId !== e &&
        (this.floorsViewData.transitionToFloorInstant(e), this.engine.broadcast(new EndMoveToFloorMessage(e, this.floorsViewData.getFloorName(e))))
    }
    this.updateFloorSelectMode = () => {
      var e
      null === (e = this.floorsSelectModeHelper) || void 0 === e || e.update()
    }
    this.floorSelectFeatureEnabledCheck = () => {
      const e = this.settingsData.tryGetProperty(keyConst.rule.features.floorselect, !0),
        t = this.settingsData.tryGetProperty(optionsKeyEnum.FloorSelect, !0),
        i = this.applicationData.application === appTypeMin.WORKSHOP
      this.toggleFloors(i || (e && t))
    }
  }
  updateCurrentFloor: any
  async init(e, t: EngineContext) {
    this.engine = t
    this.config = e
    ;[this.floorsData, this.settingsData, this.applicationData, this.sweepData, this.viewmodeData] = await Promise.all([
      t.market.waitForData(FloorsData),
      t.market.waitForData(SettingsData),
      t.market.waitForData(ApplicationData),
      t.market.waitForData(SweepData),
      t.market.waitForData(ViewmodeData)
    ])
    const i = await t.getModule(LocaleModule)
    const n = {
      floorChangesEnabled: () => this.config.allowFloorChanges,
      roomNavFeatureEnabled: () => this.settingsData.tryGetProperty(keyConst.rule.features.roomnav, !1)
    }
    this.floorsViewData = new FloorsViewData(this.floorsData, this.viewmodeData, this.sweepData, this.applicationData, i.t.bind(i), n)
    this.floorSelectFeatureEnabledCheck()
    t.market.register(this, FloorsViewData, this.floorsViewData)
    ;[this.cameraData, this.input, this.raycasterData] = await Promise.all([
      t.market.waitForData(CameraData),
      t.getModuleBySymbol<InputIniModule>(SymbolList.INPUT),
      t.market.waitForData(RaycasterData)
    ])
    if (this.config.allowFloorChanges && this.viewmodeData.isInside() && this.sweepData.currentSweepObject) {
      const e = this.sweepData.currentSweepObject.floorId
      e && (te.debug(`Set initial floor to ${e} from current sweep`), this.updateCurrentFloor(e))
    }
    const [s, a] = await Promise.all([t.getModule(CameraModule), t.market.waitForData(MeshData)])
    this.floorNavigation = new FloorsNavigation(
      t,
      this.floorsData,
      this.floorsViewData,
      this.sweepData,
      this.cameraData,
      s,
      this.viewmodeData,
      this.updateCurrentFloor,
      a
    )
    this.floorsSelectModeHelper = new FloorsSelectModeHelper(this.floorsViewData, this.viewmodeData, this.cameraData.pose)
    const l = new FloorsRenderer(
      this.floorsSelectModeHelper.getAngleModifier,
      this.cameraData.pose,
      this.floorsViewData,
      this.viewmodeData,
      this.raycasterData,
      a,
      browserUtil.canTouch()
    )
    t.addComponent(this, l),
      this.settingsData.tryGetProperty(keyConst.rule.features.roomnav, !1) && this.config.allowFloorChanges && this.registerFloorHoverCursorEffect(),
      this.bindings.push(
        this.registerKeys(),
        t.subscribe(ApplicationChangeMessage, this.applicationChanged),
        this.floorsData.onChanged(this.floorsViewData.updateViewData),
        t.subscribe(EndMoveToSweepMessage, this.onEndMoveToSweepMessage),
        t.subscribe(
          BeginSwitchViewmodeMessage,
          (function (e, t, i) {
            let n = !1
            return s => {
              const r = e.tryGetData(TourData)
              if (!r || (r && r.isTourActive())) return
              isPanOrMesh(s.toMode) && (n = null !== i.currentFloorId)
              const o = isPanOrMesh(s.fromMode),
                a = s.toMode === viewmodeEnum.Floorplan,
                l = s.toMode === viewmodeEnum.Dollhouse
              if (!o || (!l && !a)) return
              const c = n || a ? i.currentFloorId : null
              t(new MoveToFloorCommand(c, !0, 0))
            }
          })(t.market, t.commandBinder.issueCommand, this.floorsViewData)
        ),
        t.commandBinder.addBinding(MoveToFloorCommand, this.onMoveToFloorCommand),
        t.commandBinder.addBinding(MoveToFloorIndexCommand, this.onMoveToFloorIndexCommand),
        t.commandBinder.addBinding(ShowAllFloorsCommand, this.onShowAllFloorsCommand),
        t.subscribe(EndSwitchViewmodeMessage, this.updateFloorSelectMode),
        this.cameraData.pose.onChanged(this.updateFloorSelectMode),
        this.floorsViewData.onChanged(this.updateFloorSelectMode),
        this.settingsData.onPropertyChanged(keyConst.rule.features.floorselect, this.floorSelectFeatureEnabledCheck),
        this.settingsData.onPropertyChanged(optionsKeyEnum.FloorSelect, this.floorSelectFeatureEnabledCheck),
        this.applicationData.onPropertyChanged("application", this.floorSelectFeatureEnabledCheck)
      ),
      this.updateFloorSelectMode()
  }
  onUpdate() {}
  toggleFloors(e) {
    e || null === this.floorsViewData.currentFloorId || this.updateCurrentFloor(null), (this.config.allowFloorChanges = e), this.updateFloorSelectMode()
  }
  registerKeys() {
    return this.input.registerHandler(KeyEvent, async e => {
      if (!this.cameraData.canTransition()) return
      const t = e.modifiers.shiftKey
      if (e.state === KeyState.PRESSED)
        switch (e.key) {
          case hotKeyEnum.UPARROW:
            t && this.floorNavigation.moveFloorUp()
            break
          case hotKeyEnum.DOWNARROW:
            t && this.floorNavigation.moveFloorDown()
            break
          case hotKeyEnum.R:
            this.floorNavigation.moveFloorUp()
            break
          case hotKeyEnum.F:
            this.floorNavigation.moveFloorDown()
            break
          case hotKeyEnum.Y:
            this.floorNavigation.moveToFloor(null)
        }
    })
  }
  registerFloorHoverCursorEffect() {
    const e = Comparator.is(e => roomFunc.isRoomMesh(e) && e.raycastEnabled && this.floorsViewData.floorSelectable)
    const t = new AggregateSubscription(
      this.input.registerMeshHandler(HoverEvent, e, e => {
        this.engine.commandBinder.issueCommand(new SetMouseCursorCommand(cursorEnum.FINGER))
      }),
      this.input.registerMeshHandler(UnhoverEvent, e, e => {
        this.engine.commandBinder.issueCommand(new SetMouseCursorCommand(cursorEnum.DEFAULT))
      })
    )
    t.cancel()
    const i = (() => {
      let e = !1
      return () => {
        const i = this.floorsViewData.floorSelectModeEnabled
        i !== e && ((e = i), e ? t.renew() : (t.cancel(), this.engine.commandBinder.issueCommand(new SetMouseCursorCommand(cursorEnum.DEFAULT))))
      }
    })()
    i()
    this.bindings.push(this.viewmodeData.onChanged(i), this.floorsViewData.onFloorSelectModeChange(i), this.floorsViewData.makeFloorChangeSubscription(i), t)
  }
}
